package stv5;

import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import stv5.abstracted.Database;
import stv5.abstracted.EpisodeManager;

/**
 * The Settings Manager class
 * 
 * @author Daniel
 *
 */
public class Settings {
	private EpisodeManager em;
	private Database db;	
		
	private int oldDuration = 60*60*24*30;
	private int[] oldColor = {0x33, 0x33, 0x33};
	private int[] newColor = {0xcc, 0x99, 0x00};	
	private String localPlayer;
	private boolean localPlayerManual=false; // whether or not localPlayer was set manually
	
	public Settings(EpisodeManager em, Database db) {
		this.em = em;
		this.db = db;
		
		reload();
	}
	
	/**
	 * Reload settings
	 */
	public void reload() {		
		System.out.println("* Loading settings... ");
		
		// have our episode manager reload its data
		em.reload();
		
		System.out.print(" - Loading series");		
		for (Series s : db.reloadSeries()) {
			em.manageSeries( s );
			System.out.print(".");
		}
		System.out.println(" Done ("+em.size()+")");

		System.out.print(" - Loading misc settings");
		oldDuration = db.loadOldDuration();
		System.out.print(".");
		oldColor = db.loadOldColor();
		System.out.print(".");
		newColor = db.loadNewColor();
		System.out.print(".");
		if (!localPlayerManual)
			// if it was manually set, don't overwrite it!
			localPlayer = db.loadLocalPlayer();
		System.out.println(". Done.");
	}
	
	public List<Episode> getEpisodes(int seriesId) {
		return em.getEpisodes(seriesId);
	}
	
	public List<Episode> getEpisodes(Series s) {
		return getEpisodes(s.getId());
	}
	
	/**
	 * @param s
	 * @return The next Episode for a series, if available,
	 * 	or null
	 */
	public Episode getNextFor(Series s) {
		List<Episode> list = getEpisodes(s);		
		int nextId = s.getLastPlay()+1;
		return (list != null && nextId < list.size()) ? list.get(nextId) : null;
	}
	
	/**
	 * @param s
	 * @return The last viewed Episode for a series, if available,
	 * 	or null
	 */
	public Episode getLastFor(Series s) {
		List<Episode> list = getEpisodes(s);
		int lastId = s.getLastPlay();
		return (list != null && lastId >= 0 && lastId < list.size()) ? list.get(lastId) : null;
	}
		
	public Collection<Series> getSeries() {
		return db.getSeries();
	}
	
	public Series getSeries(int seriesId) {
		return db.getSeries(seriesId);
	}	
	
	public boolean hasSeries(int seriesId) {
		return db.hasSeries(seriesId);
	}	
	
	public boolean hasSeries(String folder) {
		return db.hasSeries(folder);
	}
	
	public void updateSeries(Series series) {
		db.updateSeries(series);
	}
	
	public void rebuildDb(HashMap<String, String> seriesData,
			boolean deleteOld) {
		db.rebuildDb(seriesData, deleteOld);
	}
	
	/**
	 * @param series
	 * @return True if episodes exist for the series and if
	 * 	it is is "done," which means there are no more episodes 
	 * 	available after the "current" one
	 */
	public boolean seriesIsDone(Series series) {
		List<Episode> eps = getEpisodes(series.getId());		
		return (eps != null && eps.size() > 0 && series.getLastPlay()+1 >= eps.size());		
	}
	
	/**
	 * @param series
	 * @return True if there are no episodes for the given series
	 */
	public boolean seriesIsMissing(Series series) {
		List<Episode> eps = getEpisodes(series.getId());
		return eps == null || eps.size() == 0;
	}
	
	public String getLocalForEpisode(Series s, Episode e) {
		return em.getLocalForEpisode(s, e);
	}
	
	public SeriesList spiderFolders() {
		return em.spiderFolders();
	}
	
	public SeriesList spiderFolders(String folder) {
		return em.spiderFolders(folder);
	}

	public String getTimingColor(Series ser) {
		return getTimingColor(ser, oldColor, newColor);
	}
	
	public String getTimingColor(Series ser, String colorFrom, String colorTo) {
		return getTimingColor(ser, hexToInts(colorFrom), hexToInts(colorTo));
	}
	
	public String getTimingColor(Series ser, int[] colorFrom, int[] colorTo) {
		// shortcut; if it's not recent, return the oldColor
		if (!seriesIsRecent(ser))			
			return "rgb(" + colorFrom[0] + "," + colorFrom[1] + "," + colorFrom[2] + ")";
				
		double perc = getTimingPercent(ser);
		int[] thisColor = generateColorSplit(colorFrom, colorTo, perc);
		return "rgb(" + thisColor[0] + "," 
					+ thisColor[1] + ","
					+ thisColor[2] + ")";
	}
	
	public double getTimingPercent(Series ser) {
		if (!seriesIsRecent(ser))
			return 0;
		
		int oldDateSecs = getTimeInSecs();		
		oldDateSecs -= oldDuration;
		
		double perc = ((double)ser.getLastView()-oldDateSecs) / oldDuration;
		perc = (perc < 0) ? 0 : perc;
		return perc;
	}
	
	public void handleRequest(StringBuffer buff, Request request) {
		em.handleRequest(buff, request);		
	}
	
	public boolean seriesIsRecent(Series ser) {
		int oldDateSecs = getTimeInSecs();		
		oldDateSecs -= oldDuration;		
		return (ser.getLastView() >= oldDateSecs);
	}
	
	/**
	 * @return The current time in seconds (measured from GMT Epoch)
	 * @see Calendar#getTimeInMillis()
	 */
	public static int getTimeInSecs() {
		return Integer.parseInt(""+Calendar.getInstance().getTimeInMillis()/1000);
	}
	
	/**
	 * Translates a string representation of a color in hex (eg: #FF0000 or 00FF00)
	 * 	into an int[3] where the indicies are the int values of RGB, respectively 
	 * 
	 * @param hexColor
	 * @return
	 */
	public static int[] hexToInts(String hexColor) {
		int ret[] = new int[3];
		int start = 0;
		if (hexColor.charAt(0) == '#') 
			start++;
				
		for (int i=0, j=start, k=start+2; i<3; i++, j+=2, k+=2) 
			ret[i] = Integer.parseInt(hexColor.substring( j, k), 16);
		
		return ret;
	}
	
	/**
	 * Create a new color that is perc percent between "from" and "to". 100%
	 *  would just return "to" and 0% would just return "from"
	 * 
	 * @param from
	 * @param to
	 * @param perc a double between 0 - 1
	 * @return
	 */
	private static int[] generateColorSplit(int[] from, int[] to, double perc) {
		int[] ret = new int[3];
		for (int i=0; i<3; i++) 
			ret[i] = (int) (perc*((double)to[i]-from[i])) + from[i];
		
		return ret;
	}

	public String getLocalPlayerLoc() {
		return localPlayer;
	}
	
	public void setLocalPlayerLoc(String path) {
		localPlayer = path;
		localPlayerManual = true;
	}

	public void appendSettingsList(HashMap<String, String> links) {
		em.appendSettingsList(links);		
	}

}
